#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include "tab.h"

#define POIDS_DE_HAMMING 0
#define DEBBUG 0

int IP_inv[]={-1,
			40, 	8, 	48, 	16, 	56, 	24, 	64, 	32,
			39, 	7, 	47, 	15, 	55, 	23, 	63, 	31,
			38, 	6, 	46,	14, 	54,	22, 	62, 	30,
			37, 	5, 	45, 	13, 	53, 	21, 	61, 	29,
			36, 	4,	44, 	12, 	52, 	20, 	60, 	28,
			35, 	3, 	43, 	11, 	51, 	19, 	59, 	27,
			34, 	2, 	42, 	10, 	50, 	18, 	58, 	26,
			33, 	1, 	41, 	9,	49, 	17, 	57, 	25
};

int IP[]={-1,
			58,	50,	42,	34,	26,	18,	10,	2,
			60,	52,	44,	36,	28,	20,	12,	4,
			62,	54,	46,	38,	30,	22,	14,	6,
			64,	56,	48,	40,	32,	24,	16,	8,
			57,	49,	41,	33,	25,	17,	9,	1,
			59,	51,	43,	35,	27,	19,	11,	3,
			61,	53,	45,	37,	29,	21,	13,	5,
			63,	55,	47,	39,	31,	23,	15,	7
};

int E[]={-1,
			32,	1,	2,	3,	4,	5,
			4,	5,	6,	7,	8,	9,
			8,	9,	10,	11,	12,	13,
			12,	13,	14,	15,	16,	17,
			16,	17,	18,	19,	20,	21,
			20,	21,	22,	23,	24,	25,
			24,	25,	26,	27,	28,	29,
			28,	29,	30,	31,	32,	1	
};

int PC1[]={-1,
	57,	49,	41,	33,	25,	17,	9, -1,
	1,	58,	50,	42,	34,	26,	18, -1,
	10,	2,	59,	51,	43,	35,	27, -1,
	19,	11,	3,	60,	52,	44,	36, -1,
	63,	55,	47,	39,	31,	23,	15, -1,
	7,	62,	54,	46,	38,	30,	22, -1,
	14,	6,	61,	53,	45,	37,	29, -1,
	21,	13,	5,	28,	20,	12,	4, -1
};

int PC2[]={-1, 
	14,	17,	11,	24,	1,	5,
	3,	28,	15,	6,	21,	10,
	23,	19,	12,	4,	26,	8,
	16,	7,	27,	20,	13,	2,
	41,	52,	31,	37,	47,	55,
	30,	40,	51,	45,	33,	48,
	44,	49,	39,	56,	34,	53,
	46,	42,	50,	36,	29,	32
};

int S[8][4][16] = {
	{
		{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
		{0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
		{4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
		{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}
	},
	{
		{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
		{3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
		{0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
		{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}
	},
	{
		{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
		{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
		{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
		{1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}
	},
	{
		{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
		{13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
		{10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
		{3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}
	},
	{
		{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
		{14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
		{4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
		{11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}
	},
	{
		{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
		{10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
		{9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
		{4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}
	},
	{
		{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
		{13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
		{1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
		{6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}
	},
	{
		{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
		{1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
		{7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
		{2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}
	}
};

int Per[32]={16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25};

char* int2bits(int i) {
	switch(i) {
		case 0: return  "0000";
		case 1: return  "0001";
		case 2: return  "0010";
		case 3: return  "0011";
		case 4: return  "0100";
		case 5: return  "0101";
		case 6: return  "0110";
		case 7: return  "0111";
		case 8: return  "1000";
		case 9: return  "1001";
		case 10: return "1010";
		case 11: return "1011";
		case 12: return "1100";
		case 13: return "1101";
		case 14: return "1110";
		case 15: return "1111";
		default: return NULL;
	}	
	return NULL;
}

int getRow(char *c, int index) {
	char p,d;
	p=c[index];
	d=c[index+5];
	return 2*(p-'0')+(d-'0');
}

int getColumn(char *c, int index) {
	char b1,b2,b3,b4;
	b1=c[index+1];
	b2=c[index+2];
	b3=c[index+3];
	b4=c[index+4];
	return 8*(b1-'0')+4*(b2-'0')+2*(b3-'0')+1*(b4-'0');
}

int bin2int(char *filename) {
  int res;
  char *tmp;
  tmp=(char *)malloc(6*sizeof(*tmp));
  strncpy(tmp, filename+strlen(filename)-10, 6);

  res=32*(tmp[0]-'0')
    +16*(tmp[1]-'0')
    +8*(tmp[2]-'0')
    +4*(tmp[3]-'0')
    +2*(tmp[4]-'0')
    +1*(tmp[5]-'0')
    ;

  free(tmp);

  return res;
}

/*
** Poids de hamming de la chaine sz
*/
int hamming(char *sz, int stop) {
	int i;
	int res;
	char *tmp;
	
	res=0;
	tmp=sz;
	for(i=0;i<stop;++i) {
		if(*sz=='1') res++;
		sz++;
	}	
	
	return res;
}



int* dea(int key[64],int messageL[32],int messageR[32] ) {
	char c;
	char d;
	char e;
	char f;
	char tmp;
	char k[64];
	char m[64];
	char m2[64];
	char L[32];
	char R[32];
	char RE[48]; // E(R), 48 bits
	char KP[64-8];
	char K1[16][48]; // subkeys
	char ExorK[48]; // ExorK = E^K, 48 bits
	char res[33]; // 32bits
	char P[33];
	char LR[64]; //pre output
	char cipher[64]; //output
	int i;
	int j;
	int z;
	int l;
	int rd;
	int a1,a2;
	int index_k,index_m;
	int n0,n1;
	int Tab_k_m[4][64][64]; // tab_k_m[attacked_bit][key][msg]
	int round;
  	int* ct;
	ct=calloc(64,sizeof(int));
	round=3;
	index_k=0;
	index_m=0;
	
	for(i=0;i<4;++i) {
		for (a1=0; a1<64; a1++) {
			for (a2=0; a2<64; a2++) {
				Tab_k_m[i][a1][a2]=42;
			}
		}
	}

	n0=0;
	n1=0;
/*printf("\t");
for(i=0;i<32;i++)
  printf("%d",messageL[i]);
for(i=0;i<32;i++)
  printf("%d",messageR[i]);
printf("\n");
*/
			for(i=0;i<32;i++){
			if(messageL[i]==0){
				m[i]='0';}
			else{
				if(messageL[i]==1)
				m[i]='1';

				else{printf("probleme dans le message L : %d\n",messageL[i]);}
			
			}
			}
				for(i=0;i<32;i++){
			if(messageR[i]==0){
				m[i+32]='0';}

			if(messageR[i]==1)
				m[i+32]='1';

			if ((messageR[i]!=0)&& (messageR[i]!=1)){printf("probleme dans le message R : %d\n",messageR[i]);}
			
			}
			
/*printf("m:\t");
for(i=0;i<64;++i) printf("%c", m[i]);
printf("\n");		  	*/
			strncpy(m2, m, 64);

			for(i=0;i<64;i++){
			if(key[i]==0){
				k[i]='0';}
			if(key[i]==1)
				k[i]='1';

			if(key[i]!=0&&key[i]!=1){printf("probleme dans la cle : %d\n",key[i]);}
			
			}
/*
printf("k:\t");
for(i=0;i<64;++i) printf("%c", k[i]);
printf("\n");
*/	
		for(i=0;i<64;++i) m[i]=m2[i];			

			

			// Expansion function (E)
			strncpy(L, m, 32);
			strncpy(R, m+32, 32);


			

			// Key schedule
		for(i=1,j=0;i<=64;++i) {
				if(i%8!=0) {
					KP[j]=k[PC1[i]-1];
					j++;
				}
			}

		for(rd=0;rd<16;rd++){
			
			
			if( (rd == 0) || (rd == 1) ||(rd == 8) ||(rd == 15) ){
				c=KP[0];
				d=KP[28];
		   		for(i=0;i<=54;++i) KP[i] = KP[i+1];
				KP[55] = d;
		    		KP[27] = c;
			}
			else{
				c=KP[0];
				d=KP[1];
				e=KP[28];
				f=KP[29];
		   		for(i=0;i<=54;++i) KP[i] = KP[i+2];
				KP[54] = e;
				KP[55] = f;
		    		KP[26] = c;
				KP[27] = d;
			}
		   
			for(i=0;i<48;++i) K1[rd][i]=KP[PC2[i+1]-1];
		   
		}



			
			for(rd=0;rd<round;rd++){
				for(i=0;i<48;++i) RE[i]=R[E[i+1]-1];
			
//printf("R:\t");
//for(i=0;i<32;++i) printf("%c",R[i]);
//printf("\n");
			
			//for(i=1;i<=64;++i) m[i]=m2[IP[i]];
			//for(i=0;i<48;++i) ExorK[i]='0'+(RE[i]^k[i]);
			

//printf("k:\t");
//for(i=0;i<64;++i) printf("%c", k[i]);
//printf("\n");
			
			
			
				for(i=0;i<48;++i) ExorK[i]='0'+(K1[rd][i]^RE[i]);
/*									
printf("ExorK:\t");
for(i=0;i<48;++i) printf("%c", ExorK[i]);
printf("\n");
*/		
				for(i=0;i<8;++i) {
					strncpy(res+4*i, int2bits(S[i][getRow(ExorK, 6*i)][getColumn(ExorK, 6*i)]), 4);
//printf("i=%d j=%d k=%d\n",getRow(ExorK,6*i),getColumn(ExorK,6*i),S[i][getRow(ExorK,6*i)][getColumn(ExorK,6*i)]); 
				}
				res[32]=0;
						
//printf("res:\t%s\n", res);
//printf("P:\t");
				for(i=0;i<32;i++){
					P[i] = res[Per[i]-1];
//			printf("%c", P[i]);
				}
				P[32]=0;
//			printf("\n");

				//writing of blocs L and R
				for(i=0;i<32;++i){
					tmp=L[i];
					L[i]=R[i];
					R[i]='0'+(tmp^P[i]);
				}
//printf("L:\t");
//for(i=0;i<32;++i) printf("%c", L[i]);
//printf("\n");

//printf("R:\t");
//for(i=0;i<32;++i) printf("%c", R[i]);
//printf("\n");

			}//end round
			

			if(round==3){	
				for(i=0;i<32;i++){
					LR[i+32] = R[i];
					LR[i] = L[i];
				}
//printf("\nLR:\t");
//for(i=0;i<64;++i) printf("%c",LR[i]);
//printf("\n");
		
				for(i=0;i<64;i++){
				cipher[i] = LR[i];
				}
/*
printf("cipher:\t");
for(i=0;i<64;++i) printf("%c",cipher[i]);
printf("\n");
*/			}
			
	
for(i=0;i<64;i++){
if(cipher[i]=='0')ct[i]=0;
else{
	if(cipher[i]=='1')ct[i]=1;
	else printf("probleme dans le chiffré\n");
	}


}

	return ct;	
}
